import common
from eth_keys import keys
import aiohttp
from aiohttp import web
import base64
# from binascii import b2a_hex, a2b_hex

from .myDH import DH  
from encrypter import MyAES
import json
from collections.abc import Callable

class NonceChannel_DU:
    def __init__(
        self,
        target_http_address:str,
        account_private_key:keys.PrivateKey,
        target_account_address:str,
    ):
        self.his_address = target_account_address # 对方account地址
        self.target_http_address = target_http_address
        # +++
        self.secret = str(account_private_key)
        self.my_address = account_private_key.public_key.to_checksum_address()
        self.my_pub_arg = self.my_address
        self.his_pub_arg = self.his_address
        self.dh = DH(self.my_pub_arg,self.his_pub_arg)
        self.my_pub_key = self.dh.generate_pub_key(self.secret)
        self.his_pub_key = None
        # +++
        self.shared_key = None
        self._AES = None
        self.resp_json_content:dict = None

    def get_shared_key(self):
        return self.shared_key

    async def send_request(
        self,
        ex_msg_to_send,
    )->web.Response:
        send_info = {
            "address":self.my_address,
            "DH_PK":self.my_pub_key,
            "ex_msg":ex_msg_to_send
        }
        info = json.dumps(send_info)
        async with aiohttp.request("POST",self.target_http_address, data=info) as resp:
            return resp 
        raise Exception(f"未能成功向 {self.target_http_address} 发送请求")

    async def receive_response(self,respJson:dict)->dict:
        # print(await resp.text())
        # respJson = await resp_request.json()
        self.his_pub_key = respJson["DH_PK"]
        self.shared_key = self.dh.calcu_shared_key(self.secret,self.his_pub_key)
        self._AES = MyAES(self.shared_key)
        content = base64.b64decode(respJson["content"].encode("utf-8"))
        content = self._AES.decrypt(content)
        self.resp_json_content:dict = json.loads(content)
        # final info
        """
        ABE_key_txn_id = json_content["transaction_id"]
        contract_address = json_content["contract_address"]
        contract_abi = json_content["contract_abi"]
        contract_src = json_content["contract_src"]
        """
        return self.resp_json_content
        # raise Exception("安全通道建立失败")

class NonceChannel_DO:
    def __init__(
        self,
        target_http_address:str,
        account_private_key:keys.PrivateKey,
    ):      
        self.target_http_address = target_http_address
        self.his_address = None # 对方account地址
        self.my_acct_priv_key = account_private_key  
        self.my_address = self.my_acct_priv_key.public_key.to_checksum_address()
        self.shared_key = None
        self.dh:DH = None
        self.my_pub_key = None
        
    
    def get_shared_key(self):
        return self.shared_key

    async def gen_shared_key(self,requestJson:dict)->web.Response:
        self.his_address = requestJson["address"]
        his_pub_key = requestJson["DH_PK"]
        secret = str(self.my_acct_priv_key)
        my_pub_arg = self.my_address
        his_pub_arg = self.his_address
        self.dh = DH(his_pub_arg,my_pub_arg) # 注意，这里和 DU 的是反的
        self.my_pub_key = self.dh.generate_pub_key(secret)
        self.shared_key = self.dh.calcu_shared_key(secret,his_pub_key)
        return self.shared_key
        
    async def respond(
        self,
        ABE_key_txn_id,
        contract_address,
        contract_abi,
        contract_src,
    )->web.Response:
        self._AES = MyAES(self.shared_key)
        self.send_content = json.dumps({
            "transaction_id":ABE_key_txn_id,
            "contract_address":contract_address,
            "contract_abi":contract_abi,
            "contract_src":contract_src,
        })
        encrypted_content = base64.b64encode(self._AES.encrypt(self.send_content))
        send_info = {
            "address":self.my_address,
            "aggree":True,
            "DH_PK":self.my_pub_key,
            "content":encrypted_content.decode("utf-8")
        }
        # x = send_info # 别名。。。
        # return web.json_response(x)
        info = json.dumps(send_info)
        async with aiohttp.request("POST",self.target_http_address, data=info) as resp:
            return resp 
        raise Exception("安全通道建立失败")
